AWS System Managerセッションマネージャーでポートフォワードする
AWS System Managerセッションマネージャーを利用し、SSM エージェントのインストール先インスタンスからローカルに対してポートフォワードする手順を紹介します。
ユースケース
リモートの Windows サーバーにリモートデスクトップ(RDP)でアクセスするケースを考えます。
本機能を利用することで、以下のようなメリットがあります。
- リモート VPC のセキュリティグループで RDP ポートを開けなくてよい
- RDP ポート(3389)のアウトバウンド通信が許可されていなくても、セッションマネージャーが利用するHTTPS(443) ポートだけで RDP 可能
- プライベートサブネットのサーバーに対して、踏み台を経由せずに直接 RDP 可能
- リモートサーバーに SSH をインストールしなくてよい
注意点として、ポートフォワード出来るのは、リモートサーバー内で LISTEN しているポートのみです(SSH ポートフォワードで言うところの$ ssh -L 9999:localhost:80 user@SERVER
)。
リモートサーバーからアクセス可能な別サーバーのポートはフォワードできないことにご注意ください(SSH ポートフォワードで言うところの $ ssh -L 9999:MySQL:3306 user@SERVER
)。例えば、EC2を踏み台にして、RDS に接続することはできません。
そのようなケースに対応するには SSH 版 Systems Manager セッションマネージャーの利用を検討ください。
コマンド体系
端的に言えば、AWS System Managerセッションマネージャー接続時と同じコマンド体系です。
違いは、ポートフォワード用ドキュメント(AWS-StartPortForwardingSession)を指定し、リモート・ローカルのポートを指定する引数が増えただけだけです。
System Managerセッションマネージャー接続コマンド
$ aws ssm start-session --target i-123
System Managerセッションマネージャーポートフォワードコマンド
$ aws ssm start-session --target i-123 \ --document-name AWS-StartPortForwardingSession \ --parameters '{"portNumber":["80"],"localPortNumber":["8000"]}'
セッションマネージャーの利用環境が整っていない場合、まずは次のドキュメントを元に環境を整えてください。
Getting Started with Session Manager - AWS Systems Manager
やってみた
リモートサーバーの 80 番ポートで起動する nginx にポートフォワードしてみます。
1. System Managerエージェントのアップデート
本機能を利用するには、System Managerエージェントのバージョンが 2.3.672.0 以上である必要があります。 これよりも古い場合は、エージェントを最新版にアップデートしてください。
SSM を利用し、ドキュメント AWS-UpdateSSMAgent を RunCommand すればアップデートされます。
2. Session Managerプラグインのアップデート
本機能を利用するには、Session Managerプラグインのバージョンが 1.1.26.0 以上である必要があります。
これよりも古い場合は、プラグインを最新版にアップデートしてください。
# アップデート $ curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip" $ unzip sessionmanager-bundle.zip $ sudo ./sessionmanager-bundle/install \ -i /usr/local/sessionmanagerplugin \ -b /usr/local/bin/session-manager-plugin # バージョンチェック $ session-manager-plugin --version 1.1.31.0
3. ポートフォワード
セッションマネージャーでポートフォワードするには
ポートフォワード用ドキュメント(AWS-StartPortForwardingSession)を指定し、リモート・ローカルのポートを指定するだけです。
$ aws ssm start-session --target $INSTANCE_ID \ --document-name AWS-StartPortForwardingSession \ --parameters '{"portNumber":["80"],"localPortNumber":["8000"]}' Starting session with SessionId: botocore-session-1569008417-05521c0a55edb2d55 Port 8000 opened for sessionId botocore-session-1569008417-05521c0a55edb2d55.
localPortNumber
を省略すると、自動で空いているポートが割り振られます。
$ aws ssm start-session --target $INSTANCE_ID \ --document-name AWS-StartPortForwardingSession \ --parameters '{"portNumber":["80"]}' Starting session with SessionId: botocore-session-1569064990-098c3a6376b82743c Port 51959 opened for sessionId botocore-session-1569064990-098c3a6376b82743c.
このケースだと51959
です。
リモートのポート番号(portNumber
)を省略すると、80番ポートが利用されます。
4. 接続確認
別ターミナルで、ローカルポートに対してアクセスしてみます。
$ curl -I localhost:51959 HTTP/1.1 200 OK Server: nginx/1.12.2 Date: Sat, 21 Sep 2019 11:23:27 GMT Content-Type: text/html Content-Length: 3520 Last-Modified: Wed, 28 Aug 2019 19:52:13 GMT Connection: keep-alive ETag: "5d66db6d-dc0" Accept-Ranges: bytes
確かに、ポートフォワードされていますね。
ポートフォワードアクティヴィティを監視
本機能を利用すると、意図的に特定ポートの通信を塞ぐようにネットワーク設計した環境において、利用者がその制約を回避できてしまう可能性があります。
SSMエージェントや素のセッションマネージャーは、運用面のメリットから許容するとして、過度なポートフォワードの利用には監視の目を光らせたい場合は、CloudTrail を有効化し
- CloudWatch Events を使って StartSession の API 呼び出しをリアルタイム監視
- Athena を使って CloudTrail ログ から StartSession の API 呼び出しをバッチ監視
してください。
SSM:StartSession
すると CloudTrail には以下の様なログが残ります。
{ "eventVersion": "1.05", "userIdentity": { "type": "AssumedRole", "principalId": "...", "arn": "arn:aws:sts::1234:assumed-role/...", "accountId": "1234", "accessKeyId": "...", "sessionContext": { ... } }, "eventTime": "2019-09-21T11:28:18Z", "eventSource": "ssm.amazonaws.com", "eventName": "StartSession", "awsRegion": "eu-central-1", "sourceIPAddress": "1.2.3.4", ... "requestParameters": { "target": "i-1234", "documentName": "AWS-StartPortForwardingSession", "parameters": { "localPortNumber": [ "8000" ], "portNumber": [ "80" ] }, "responseElements": { ... }, "requestID": "...", "eventID": "...", "resources": [ { "accountId": "1234", "ARN": "arn:aws:ec2:eu-central-1:1234:instance/i-1234" }, { "accountId": "1234", "ARN": "arn:aws:ssm:eu-central-1::document/AWS-StartPortForwardingSession" } ], "eventType": "AwsApiCall", "recipientAccountId": "1234" }
ドキュメント AWS-StartPortForwardingSession の仕様を確認
- PortNumber(フォワードされるリモートサーバーのポート)
- localPortNumber(フォワード先のローカルサーバーのポート)
が定義されているだけです。
{ "schemaVersion": "1.0", "description": "Document to start port forwarding session over Session Manager", "sessionType": "Port", "parameters": { "portNumber": { "type": "String", "description": "(Optional) Port number of the server on the instance", "allowedPattern": "^([1-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$", "default": "80" }, "localPortNumber": { "type": "String", "description": "(Optional) Port number on local machine to forward traffic to. An open port is chosen at run-time if not provided", "allowedPattern": "^([0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$", "default": "0" } }, "properties": { "portNumber": "{{ portNumber }}", "type": "LocalPortForwarding", "localPortNumber": "{{ localPortNumber }}" } }
最後に
AWS Systems Manager セッションマネージャーのポートフォワード機能を紹介しました。
SSH の複雑なオプションと格闘することなく、だれでも簡単にポートフォワードできます。
現時点ではシンプルなポートフォワードにしか対応していませんが、今後のアップデートにより、より多くの SSH ポートフォワードのケースを置き換えられるようになるのではないでしょか。
それでは。